package com.yyq.bigexport.util.export;

import cn.hutool.core.io.file.PathUtil;
import cn.hutool.core.thread.NamedThreadFactory;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yyq.bigexport.entity.User;
import com.yyq.bigexport.service.ExportService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ExcelExportUtils {
    //定义导出线程池
    private static final ThreadPoolExecutor executorService = new ThreadPoolExecutor(2,
            5,
            30,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(),
            new NamedThreadFactory("export-pool-",false));

    public static String export(ExportService exportService, LambdaQueryWrapper queryWrapper, Class<?> clazz) {
        //region # 计算
        //首次查1条(用于统计总数量、总页数)
        IPage<User> page = exportService.pageList(1, 1, queryWrapper);

        //每次查询数据量
        int pageSize = 5000;
        //每个任务查询次数，查询完毕后则生成单个文件
        int pageQueryCount = 10;
        //单sheet最大记录数
        int sheetMaxRows = pageSize * pageQueryCount;
        //总记录
        long totalRows = page.getTotal();
        //总页数
        int totalPages = Long.valueOf((totalRows + pageSize - 1) / pageSize).intValue();
        //计算的sheet数量(如果1文件1sheet，相当于文件数量)
        int sheetPageCount = Long.valueOf((totalRows + sheetMaxRows - 1) / sheetMaxRows).intValue();
        //endregion

        log.info("任务分析：总记录-{}，总页数-{}，页大小-{}", totalRows, sheetPageCount, sheetMaxRows);

        //计算完毕后开始导出
        try {
            // 创建计数器
            CountDownLatch countDownLatch = new CountDownLatch(sheetPageCount);
            long currTime = System.currentTimeMillis();
            String tmpPath = ResourceUtils.getURL("classpath:").getPath() + File.separator + "_temp_export" + File.separator + currTime;
            for (int i = 1; i <= sheetPageCount; i++) {
                String fileName = String.format("%s%s%s.xlsx", tmpPath, File.separator, i);
                //开始页
                int pageBeginIndex = ((i - 1) * pageQueryCount + 1);
                //结束页
                int pageEndIndex = pageBeginIndex + pageQueryCount - 1;
                if (pageEndIndex > totalPages) {
                    pageEndIndex = totalPages;
                }
                //统计日志
                if (i < sheetPageCount) {
                    log.warn("总数据：{}，当前分页任务：{}-{}，单次查询：{}，本次数据量：{}，累计：{}", totalRows, pageBeginIndex, pageEndIndex, pageSize, (pageEndIndex - pageBeginIndex + 1) * pageSize, pageEndIndex * pageSize);
                } else {
                    log.warn("总数据：{}，当前分页任务：{}-{}，单次查询：{}，本次数据量：{}，累计：{}", totalRows, pageBeginIndex, pageEndIndex, pageSize, totalRows - ((i - 1) * sheetMaxRows), totalRows);
                }
                executorService.submit(new ExcelExportTask(
                                fileName,
                                0,
                                exportService,
                                queryWrapper,
                                pageBeginIndex,
                                pageEndIndex,
                                pageSize,
                                countDownLatch,
                                clazz
                        )
                );
            }
            // 等待所有线程处理完成
            countDownLatch.await();
            log.warn("所有线程完成，导出数据总量：{}，共耗时：{}s!", totalRows, (System.currentTimeMillis() - currTime) / 1000);
            //返回文件名
            String fileName = String.format("%s%s%s.xlsx", tmpPath, File.separator, 1);
            if (sheetPageCount > 1) {
                log.info("准备打zip压缩包...");
                String zipPath = String.format("%s.zip", tmpPath);
                ZipUtil.zip(tmpPath, zipPath);
                log.info("打包完成：{}", zipPath);
                fileName = zipPath;
            }
            //1、打开文件、打开文件夹
            Runtime.getRuntime().exec("cmd /c start " + tmpPath);
            return fileName;
        } catch (Exception e) {
            log.error("导出异常：{}", e.getMessage(), e);
        }
        return null;
    }
}
